Crate der_parser

source ·
Expand description

License: MIT Apache License 2.0 docs.rs crates.io Download numbers Travis CI AppVeyor CI dependency status

BER/DER Parser

A parser for Basic Encoding Rules (BER [X.690]) and Distinguished Encoding Rules(DER [X.690]), implemented with the nom parser combinator framework.

It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken to ensure security and safety of this crate, including design (recursion limit, defensive programming), tests, and fuzzing. It also aims to be panic-free.

The code is available on Github and is part of the Rusticata project.

DER parser design

There are two different approaches for parsing DER objects: reading the objects recursively as long as the tags are known, or specifying a description of the expected objects (generally from the ASN.1 description).

The first parsing method can be done using the parse_ber and parse_der methods. It is useful when decoding an arbitrary DER object. However, it cannot fully parse all objects, especially those containing IMPLICIT, OPTIONAL, or DEFINED BY items.

use der_parser::parse_der;

let bytes = [ 0x30, 0x0a,
              0x02, 0x03, 0x01, 0x00, 0x01,
              0x02, 0x03, 0x01, 0x00, 0x00,
];

let parsed = parse_der(&bytes);

The second (and preferred) parsing method is to specify the expected objects recursively. The following macros can be used: parse_der_sequence_defined and similar functions, parse_der_struct, etc.

For example, to read a sequence containing two integers:

use der_parser::ber::*;
use der_parser::error::BerResult;

fn localparse_seq(i:&[u8]) -> BerResult {
    parse_der_sequence_defined!(i,
        parse_ber_integer >>
        parse_ber_integer
    )
}

let bytes = [ 0x30, 0x0a,
              0x02, 0x03, 0x01, 0x00, 0x01,
              0x02, 0x03, 0x01, 0x00, 0x00,
];
let parsed = localparse_seq(&bytes);

All functions return a BerResult object: the parsed BerObject, an Incomplete value, or an error.

Note that this type is also a Result, so usual functions (map, unwrap etc.) are available.

Notes

BER/DER Integers

DER integers can be of any size, so it is not possible to store them as simple integers (they are stored as raw bytes).

To get a simple value, use BerObject::as_u32 (knowning that this method will return an error if the integer is too large), BerObject::as_u64, or use the bigint feature of this crate and use BerObject::as_bigint.

use der_parser::ber::*;
use der_parser::error::BerResult;

let data = &[0x02, 0x03, 0x01, 0x00, 0x01];

let (_, object) = parse_ber_integer(data).expect("parsing failed");
assert_eq!(object.as_u64(), Ok(65537));

Access to the raw value is possible using the as_slice method.

Misc Notes

  • The DER constraints are verified if using parse_der.
  • BerObject and DerObject are the same objects (type alias). The only difference is the verification of constraints during parsing.

Serialization

Support for encoding BER/DER objects is currently being tested and can be used by activating the serialize feature. Note that current status is experimental.

See the ber_encode_* functions in the ber module, and BerObject::to_vec

References

  • [X.680] Abstract Syntax Notation One (ASN.1): Specification of basic notation.
  • [X.690] ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER).

Re-exports

Modules

  • Basic Encoding Rules (BER) objects and parser
  • Basic Encoding Rules (BER) objects and parser
  • Error type for BER/DER parsers
  • Object ID (OID) representations.

Macros